﻿namespace NetFx.AGIL
{
  using System;
  using System.Collections.Generic;
  using System.Text;
  using System.IO;
  using System.Reflection;
  using System.Reflection.Emit;

  /// <summary>
  /// Agil代码阅读器。
  /// </summary>
  /// <remarks>
  /// 由于不得不使用ILGenerator处理SEH和RVA，
  /// 我们已经在IL层次上引入了虚拟指令。
  /// 但是如果要真正支持RoundTrip，则一定还要
  /// 将这些虚拟指令还原到原来的位置。
  /// 所以，需要考虑支持那些真正可以还原的指令
  /// 以及在阅读器上阅读之后如何完成还原。
  /// </remarks>
  public class AgilCodeReader:IDisposable
  {
    #region Statics
    public static AgilCodeReader of(MethodBase method)
    {
      return new AgilCodeReader(method);
    }
    public static AgilCodeReader of(Module module, MethodBody methodBody)
    {
      return new AgilCodeReader(module, methodBody);
    }
    public static AgilCodeReader of(Module module, byte[] codes)
    {
      return new AgilCodeReader(module, codes);
    }
   
    #endregion
    #region Fields
    /// <summary>
    /// IL的代码流。
    /// </summary>
    protected BinaryReader binReader = null;
    /// <summary>
    /// IL代码流所在的方法（用于解析Token）。
    /// </summary>
    protected MethodBase method = null;
    protected Module module = null;
    #endregion
    #region Properties
    /// <summary>
    /// 获取代码流。
    /// </summary>
    public virtual BinaryReader BinaryReader
    {
      get
      {
        return this.binReader;
      }
    }
    /// <summary>
    /// 判别当前对象是否已经处置。
    /// </summary>
    public virtual bool IsDisposed
    {
      get
      {
        return this.method == null && this.binReader == null;
      }
    }
    /// <summary>
    /// 判断当前对象的阅读器是否可以跳读。
    /// </summary>
    public virtual bool CanSeek
    {
      get
      {
        return this.BinaryReader.BaseStream.CanSeek;
      }
    }
    /// <summary>
    /// 判别当前对象的阅读器是否已经读完。
    /// </summary>
    public virtual bool IsReadingFinished
    {
      get
      {
        return this.BinaryReader.BaseStream.Position>= this.BinaryReader.BaseStream.Length;
      }
    }
    public virtual MethodBase Method
    {
      get
      {
        return this.method;
      }
    }
    /// <summary>
    /// 获取用于解析Token的代码流所在的模块。
    /// </summary>
    public virtual Module Module
    {
      get
      {
        return this.module;
      }
    }
    /// <summary>
    /// 当前代码的读取位置。
    /// </summary>
    public virtual long Offset
    {
      get
      {
        return this.BinaryReader.BaseStream.Position;
      }
    }
    #endregion
    #region Constructors
    public AgilCodeReader(MethodBase method)
      : this( (method!=null ? method.Module : null),(method != null ? method.GetMethodBody() : null)
      )
    {
      if ((this.method = method) == null) throw new ArgumentNullException("method");
    }
    public AgilCodeReader(Module module, MethodBody methodBody)
      : this(module, methodBody != null ? methodBody.GetILAsByteArray() : new byte[0])
    {

    }
    public AgilCodeReader(Module module, byte[] codes)
      : this(module, new MemoryStream(codes))
    {

    }
    public AgilCodeReader(Module module, Stream codeStream)
      : this(module, new BinaryReader(codeStream))
    {
    }
    public AgilCodeReader(Module module, BinaryReader binReader)
    {
      if (module == null) throw new ArgumentNullException("module can not be null!");
      if (binReader == null) throw new ArgumentNullException("binReader can not be null!");
      this.module = module;
      this.binReader = binReader;
    }
    ~ AgilCodeReader()
    {
      this.Dispose();
    }
    #endregion
    #region Methods
    /// <summary>
    /// 读取下一个Agil操作。
    /// </summary>
    /// <returns>如果可以读取，返回相应对象，否则返回null。</returns>
    /// <remarks>
    /// 读取过程中可能出现异常。
    /// </remarks>
    public virtual AgilOperation Read()
    {
      try
      {
        return !this.IsReadingFinished
          ? AgilOperation.Read(this.BinaryReader, this.Module, this.Method, this.Offset)
          : null;
      }
      catch (EndOfStreamException eos)
      {
        throw new InvalidOperationException(
          "Reading over the end of stream, the stream may be corrupted!",
          eos
          );
      }
    }

    /// <summary>
    /// 跳到指定位置。
    /// </summary>
    /// <param name="offset">指定位置</param>
    /// <param name="origin">相对原点</param>
    public virtual void Seek(long offset, SeekOrigin origin)
    {
      this.BinaryReader.BaseStream.Seek(offset, origin);
    }
    /// <summary>
    /// 跳到开始。
    /// </summary>
    public virtual void Reset()
    {
      this.Seek(0L, SeekOrigin.Begin);
    }
    /// <summary>
    /// 关闭代码流。
    /// </summary>
    public virtual void Close()
    {
      this.BinaryReader.Close();
    }
    /// <summary>
    /// 处置当前对象。
    /// </summary>
    public virtual void Dispose()
    {
      this.Dispose(IsDisposed);
    }
    protected virtual void Dispose(bool disposed)
    {
      if (!disposed)
      {
        try
        {
          this.binReader.Close();
        }
        finally
        {
          this.binReader = null;
        }
        this.method = null;
      }
    }
    #endregion
  }
}
